package cn.ciis.server;

import cn.ciis.basic.config.CiisConfig;
import cn.ciis.basic.event.CheckIpEvent;
import cn.ciis.basic.kit.ByteKit;
import cn.ciis.basic.plugin.CiisSessionContext;
import com.jfinal.kit.LogKit;
import net.dreamlu.event.EventKit;
import org.tio.core.ChannelContext;
import org.tio.core.TioConfig;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;
import org.tio.server.intf.ServerAioHandler;

import java.nio.ByteBuffer;
import java.util.Arrays;


/**
 * @author 冉志林
 */
public class CiisAioHandler  implements ServerAioHandler {

    /**
     * 解码：把接收到的ByteBuffer，解码成应用可以识别的业务消息包 总的消息结构：消息头 + 消息体 消息头结构： 4个字节，存储消息体的长度 消息体结构： 对象的json串的byte[]
     *
     * @param buffer
     * @param limit
     * @param position
     * @param readableLength
     * @param channelContext
     * @return
     * @throws AioDecodeException
     */
    @Override
    public CiisPacket decode(
            ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext)
            throws AioDecodeException {

        // 收到的数据组不了业务包，则返回null以告诉框架数据不够
        if (readableLength < CiisPacket.HEADER.length) {
            return null;
        }
        byte[] head = new byte[CiisPacket.HEADER.length];

        buffer.get(head);
        if(!Arrays.equals(CiisPacket.HEADER,head)){

            LogKit.error("{}发送的消息头不对！",channelContext.getClientNode().getIp());
            EventKit.post(new CheckIpEvent(channelContext));
            return null;
        }
        //开始组包
        CiisPacket tisPacket = new CiisPacket();

        buffer.get(tisPacket.getType());//设置帧类型
        buffer.get(tisPacket.getEnterprise());//设置企业号
        buffer.get(tisPacket.getDevice());//获取设备号
        buffer.get(tisPacket.getCmd());//获取执行命令
        buffer.get(tisPacket.getBodyLength());

        // 收到的数据是否足够组包
        int isDataEnough = readableLength - tisPacket.getNeededLength();
        // 不够消息体长度(剩下的buffer组不了消息体)
        if (isDataEnough < 0) {
            return null;
        } else {
            // 组包成功
            if (tisPacket.getBodyLen() > 0) {
                buffer.get(tisPacket.getBody());
            }
            byte[] end = new byte[CiisPacket.END.length];

            buffer.get(end);

            if(Arrays.equals(end,CiisPacket.END)){
                return tisPacket;
            }else{
                LogKit.error("数据格式不正确！");
                EventKit.post(new CheckIpEvent(channelContext));
                return null;
            }

        }
    }

    /**
     * 编码：把业务消息包编码为可以发送的ByteBuffer 总的消息结构：消息头 + 消息体 消息头结构： 4个字节，存储消息体的长度 消息体结构： 对象的json串的byte[]
     *
     * @param packet
     * @param tioConfig
     * @param channelContext
     * @return
     */
    @Override
    public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {

        CiisPacket tisPacket = (CiisPacket) packet;
        byte[] body = tisPacket.getBody();
        int bodyLen = 0;
        if (body != null) {
            bodyLen = body.length;
        }
        // buffer的总长度是 = 消息头的长度 + 消息体的长度
        int allLen =tisPacket.getSendLength(bodyLen);
        // 创建一个新的buffer
        ByteBuffer buffer = ByteBuffer.allocate(allLen);
        // 设置字节序
        buffer.order(tioConfig.getByteOrder());

        buffer.put(CiisPacket.HEADER);//消息头
        buffer.put(tisPacket.getType());//帧类型
        buffer.put(tisPacket.getEnterprise());//企业信息
        buffer.put(tisPacket.getDevice());//设备信息
        buffer.put(tisPacket.getCmd());//执行命令
        buffer.put(ByteKit.hexStr2Bytes(ByteKit.DecToHexString(bodyLen,2)));//消息长度

        // 写入消息体
        if (body != null) {
            buffer.put(body);
        }
        buffer.put(CiisPacket.END);

        return buffer;
    }

    /**
     * 处理消息
     *
     * @param packet
     * @param channelContext
     * @throws Exception
     */
    @Override
    public void handler(Packet packet, ChannelContext channelContext) {
        CiisSessionContext ciisSessionContext = (CiisSessionContext) channelContext.get("ciisSessionContext");
        CiisConfig.tioPlugs.doBusinessHandler(packet, ciisSessionContext);
    }

    public static void main(String[] args) {
        //亦或校验
        System.out.println(ByteKit.getXor((byte) 0x55,"A1A2A3A4A5"));//A1A2A3A4A5-->f4;7172737475-->24
        //CRC16 校验
        System.out.println(ByteKit.makeCrc(ByteKit.hexStr2Bytes("7172737475")));
    }
}
